namespace ActiveRecord

import System
import System.Collections.Generic

enum AssociationType: 
   BelongsTo
   HasAndBelongsToMany
   HasMany
   HasOne
   None

partial class ActiveRecordBase:
   // constants
   static final UPDATED_ON = "updated_on"
   static final UPDATED_AT = "updated_at"
   static final CREATED_ON = "created_on"
   static final CREATED_AT = "created_at"
   static final DEFAULT_IDENTITY_KEY = "id"
   static final DEFAULT_INHERITANCE_KEY = "type"
   static final DEFAULT_COUNTER_CACHE = "_count"
#   static final ACTIVE_RECORD_BASE_CLASS_NAME = "ActiveRecord.ActiveRecordBase"
   
   // properties
   BelongsTo as Dictionary [of string, BelongsToAttribute]:
      get:
         typeName = self.GetType().AssemblyQualifiedName
         return _activeRecordAttributes[typeName].BelongsToAttributes if isRegistered(typeName)
         return null

   HasOne as Dictionary [of string, HasOneAttribute]:
      get:
         typeName = self.GetType().AssemblyQualifiedName
         return _activeRecordAttributes[typeName].HasOneAttributes if isRegistered(typeName)
         return null
   
   HasMany as Dictionary [of string, HasManyAttribute]:
      get:
         typeName = self.GetType().AssemblyQualifiedName
         return _activeRecordAttributes[typeName].HasManyAttributes if isRegistered(typeName)
         return null

   HasAndBelongsToMany as Dictionary [of string, HasAndBelongsToManyAttribute]:
      get:
         typeName = self.GetType().AssemblyQualifiedName
         return _activeRecordAttributes[typeName].HasAndBelongsToManyAttributes if isRegistered(typeName)
         return null

   [Getter(Associations)]
   _associations = Dictionary [of string, ActiveTable]()
   
   AssociationTables as (string):
      get:
         return array(string, _associations.Keys)

   Columns as (string):
      get:
         return array(string, _columns.Keys)

   ContentColumns as (string):
      get:
         ret = List of string()
         for key as string in _columns.Keys:
            if not (_rePrimaryKey.IsMatch(key) or key =~ /(_id|_count)$/): # have to use re.IsMatch() becuase /${var}/ doesn't seem to work
               ret.Add(key)
         return array(string, ret)
   
   [Property(Lazy)]
   private _lazyLoading = true
   
   PrimaryKey as string:
      get:
         return _primaryKey
      set:
         _primaryKey = value
         _rePrimaryKey = Regex("${value}")
   private _primaryKey as string
   
   TableName as string:
      get:
         typeName = self.GetType().AssemblyQualifiedName
         return _activeRecordTableNames[typeName] if _activeRecordTableNames.ContainsKey(typeName)
         return null
      set:
         typeName = self.GetType().AssemblyQualifiedName
         if _activeRecordTableNames.ContainsKey(typeName):
            _activeRecordTableNames[typeName] = value 
         else:
            _activeRecordTableNames.Add(typeName, value)

   // protected/private members
   private _columns = {}
   private _rePrimaryKey as Regex
   private _taintedPK as bool
   private _taintedContent as bool
   private _taintedFKs = Dictionary[of string, string]() # tableName => fkName
   private _taintedFKAssns = Dictionary[of string, AssociationAttribute]() # fkName => AssociationAttribute

   // static properties
   static ConnectionProvider as string:
      get:
         return _connectionProvider
      set:
         _connectionProvider = value
         staticInit()
   static _connectionProvider as string

   static ConnectionString as string:
      get:
         return _connectionString
      set:
         if Utils.IsEmpty(_connectionProvider) or _connectionProvider.ToLower() == "mysql":
            _connectionString = value + "; Allow Zero Datetime=true;" // this allows mysql connection to return null datetimes (00-00-00...)
         else:
            _connectionString = value
         staticInit()
   static _connectionString as string
   
   [Property(ActiveRecordTypes)]
   private static _activeRecordTypes = Dictionary [of string, ActiveRecordBase]() # typeName => instance 
   private static _activeRecordTypeColumns = Dictionary [of string, (string)]() # typeName =>  database column names from "show columns from table" 
   private static _activeRecordTableNames = Dictionary [of string, string]() # typeName => table name
   private static _activeRecordTypeNamesShort = Dictionary [of string, string]() # type.FullName => typeName
   private static _activeRecordClasses = List [of string]() # a list of the class names of all ActiveRecordBase instances
   private static _activeRecordTables = List [of string]() # table names corresponding to _activeRecordClasses 
   private static _activeRecordAttributes =  Dictionary [of string, ActiveRecordAttributeSet]()
   private static _activeRecordInheritanceColumns = Dictionary [of string, string]() # typeName => inheritacne column
   private static _activeRecordBaseTypes = Dictionary [of string, string]() # typeName => base class name
   